package cn.mjnxin.iot.connector.base;

import cn.mjnxin.iot.base.domain.ChannelData;
import cn.mjnxin.iot.base.domain.SocketData;
import cn.mjnxin.iot.base.log.LogWorker;
import cn.mjnxin.iot.connector.cache.HostRuntimeCache;
import cn.mjnxin.iot.connector.context.ConnectorContext;
import cn.mjnxin.iot.connector.context.IPeerContext;
import cn.mjnxin.iot.connector.exception.GateNotFoundException;
import cn.mjnxin.iot.connector.exception.NetworkException;
import cn.mjnxin.iot.transfer.TransferExchange;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;

/**
 * 主动发送器
 * @author CLG 2023年10月10日
 * @version V1.0.0
 */
public interface IChannelDataSender {
	IPeerContext peerContext();

	/**
	 * @param request
	 */
	void sendChannelData(ChannelData request);
	
	String getGateAddress();
	
	/**
	 * @param outData
	 * @param pid
	 * @param logLevel 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	 * @param gateAddress
	 * @param terminalAddress
	 */
	default void sendMessage(byte[] outData, Integer pid, Integer logLevel, String gateAddress, String terminalAddress) {
		SocketData data = new SocketData(outData);
		data.setPid(pid);
		ChannelData response = new ChannelData(gateAddress, terminalAddress, pid, logLevel, data);
		response.setLogLevel(logLevel);
		
		sendChannelData(response);
	}
	
	/**
	 * @param outData
	 * @param logLevel 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	 * @param pid
	 * @param clientKey
	 * @param gateAddress
	 * @param terminalAddress
	 */
	default void sendMessage(ByteBuf outData, Integer pid, Integer logLevel, String clientKey, String gateAddress, String terminalAddress)  {
		IPeerContext context = peerContext();

		int time = 0;
		while(true) {
			try{
				context.getGateAddress(terminalAddress);
				break;
			}
			catch(GateNotFoundException ex) {
				time++;
				try {
					Thread.sleep(1000L);
				} catch (InterruptedException e1) {
				}
				if (time <= 6) {
					terminalAddress = context.getPeerAddress(clientKey);
					continue;
				}
	        	LogWorker.log("检测到 terminalAddress: " + terminalAddress + " 已经失效，断连此Terminal");
	        	final String currentTerminalAddr = terminalAddress;
	        	new Thread() {
	        		public void run() {
			            try {
			                ByteBuf unlinkBuf = TransferExchange.hostCloseTerminal(HostRuntimeCache.gateNo, pid, logLevel, currentTerminalAddr, gateAddress);
			                
			                Channel channel = HostRuntimeCache.getGateChannel(gateAddress);
			                if (channel == null) {
			                	LogWorker.error(ConnectorContext.CONNECTOR_NAME + "与网关断连，无法发送报文");
			    	            return;
			                }
			                LogWorker.log("发送断连Terminal控制报文");
			                channel.writeAndFlush(unlinkBuf);
		
				        	context.removePeer(currentTerminalAddr);
			                
			            } catch (Exception e) {
			                LogWorker.error(ex.getMessage(), ex);
			            }

	        		}
	        	}.start();
	            throw new NetworkException(ConnectorContext.CONNECTOR_NAME + "网络故障");
			}
		}
		SocketData data = new SocketData(outData);
		data.setPid(pid);
		ChannelData response = new ChannelData(gateAddress, terminalAddress, pid, logLevel, data);
		response.setLogLevel(logLevel);
		sendChannelData(response);
	}

	/**
	 * @param outData
	 * @param pid
	 * @param logLevel 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	 * @param gateAddress
	 */
	default void sendMessage(byte[] outData, Integer pid, Integer logLevel, String gateAddress)  {
		SocketData data = new SocketData(outData);
		data.setPid(pid);
		ChannelData response = new ChannelData(gateAddress, null, pid, data);
		response.setLogLevel(logLevel);
		
		sendChannelData(response);
	}
	
	/**
	 * @param outData
	 * @param pid
	 * @param logLevel 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	 * @param gateAddress
	 */
	default void sendMessage(ByteBuf outData, Integer pid, Integer logLevel, String gateAddress) {
		SocketData data = new SocketData(outData);
		data.setPid(pid);
		ChannelData response = new ChannelData(gateAddress, null, pid, data);
		response.setLogLevel(logLevel);
		
		sendChannelData(response);
	}
	
	/**
	 * 任意发送
	 * @param outData
	 * @param logLevel 日志等级 0：无日志 1：报文长度日志 2：报文内容日志 3：所有日志
	 * @throws InterruptedException
	 */
	default void sendMessage(ByteBuf outData,  Integer logLevel) throws InterruptedException {
		SocketData data = new SocketData(outData);
		ChannelData response = new ChannelData(logLevel, data);
		response.setLogLevel(logLevel);
		
		sendChannelData(response);
	}
}
